﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Reflection;

namespace Colonisator.Classes
{
    /// <summary>
    /// Définit l'ensemble des valeurs de la table de bord
    /// </summary>
    [Serializable()]
    public class TableDeBord
    {
        /// <summary>
        /// Quantité, en Kg, de pièces d'or (Dodris), dans le coffre.
        /// </summary>
        public Int32 Dodris { get; set; }

        /// <summary>
        /// Personnel à bord
        /// </summary>
        public Int32 Equipage { get; set; }

        /// <summary>
        /// Quantité, en Kg, de consommables à bord
        /// </summary>
        public double Vivres { get; set; }

        /// <summary>
        /// Expression, en Kg / homme / tour de la consommation de vivres
        /// </summary>
        public double Consommation { get; set; }
        
        /// <summary>
        /// Nombre de barils
        /// </summary>
        public Int32 Barils { get; set; }

        /// <summary>
        /// Exprimé en %, indice général d'influence sur l'équipage
        /// </summary>
        public double Influence { get; set; }

        /// <summary>
        /// Exprimé en %, le gréément évalue les pièces de manoeuvre (mâts, voiles ...)
        /// </summary>
        public double Greement { get; set; }

        /// <summary>
        /// Exprimé en %, représente l'état de la coque.
        /// </summary>
        public double Structure { get; set; }

        /// <summary>
        /// Nombre de canons à bord.
        /// </summary>
        public Int32 Canons { get; set; }

        /// <summary>
        /// Quantité, en Kg, de marchandises de contrebande à bord
        /// </summary>
        public Int32 Contrebande { get; set; }

        /// <summary>
        /// Indice de base 1, augmente directement la puissance offensive brute 
        /// </summary>
        public double ModificateurPuissance { get; set; }

        /// <summary>
        /// En %, affecte directement l'efficacité du navire
        /// </summary>
        public double ModificateurEfficacite { get; set; }

        /// <summary>
        /// Correspond au différentiel de cases max. par tour
        /// </summary>
        public Int32 ModificateurDeplacement { get; set; }

        /// <summary>
        /// contenu d'un trésor (en général provenant d'une carte)
        /// </summary>
        public TableDeBord Tresor { get; set; }

        /// <summary>
        /// Constructeur de début de partie.
        /// </summary>
        public TableDeBord(RangNavire unRang)
        {
            switch (unRang)
            {
                case RangNavire.Rang1:
                    break;
                case RangNavire.Rang2:
                    break;
                case RangNavire.Rang3:
                    break;
                case RangNavire.Rang4:
                    Dodris = 10000;
                    Equipage = 200;
                    Vivres = 8000;
                    Consommation = 2;
                    Barils = 100;
                    Influence = 100;
                    Greement = 100;
                    Structure = 100;
                    Canons = 50;
                    ModificateurPuissance = 1;
                    break;
                case RangNavire.Rang5:
                    break;
                case RangNavire.Rang6:
                    break;
                default:
                    break;
            }
        }

        public TableDeBord()
        {
        }

        /// <summary>
        /// Mets à jour la table de bord en fonction d'un delta (fournit généralement par
        /// une résolution de carte).
        /// </summary>
        /// <param name="unDelta"></param>
        /// <param name="gain">si vrai, le delta est AJOUTE, si non, il est retiré</param>
        public void MAJTableDeBordSelonDelta(TableDeBord unDelta, bool gain)
        {
            foreach (PropertyInfo prop in unDelta.GetType().GetProperties())
            {
                if (prop.PropertyType == typeof(double))
                {
                    if (Convert.ToDouble(prop.GetValue(unDelta, null)) != 0)
                    {
                        if (gain)
                            prop.SetValue(this, Convert.ToDouble(prop.GetValue(this, null)) + Convert.ToDouble(prop.GetValue(unDelta, null)), null);
                        else
                            prop.SetValue(this, Convert.ToDouble(prop.GetValue(this, null)) - Convert.ToDouble(prop.GetValue(unDelta, null)), null);
                    }
                }
                else if (prop.PropertyType == typeof(Int32))
                {
                    if (Convert.ToInt32(prop.GetValue(unDelta, null)) != 0)
                    {
                        if (gain)
                            prop.SetValue(this, Convert.ToInt32(prop.GetValue(this, null)) + Convert.ToInt32(prop.GetValue(unDelta, null)), null);
                        else
                            prop.SetValue(this, Convert.ToInt32(prop.GetValue(this, null)) - Convert.ToInt32(prop.GetValue(unDelta, null)), null);
                    }
                }
            }
        }

        /// <summary>
        /// Indice qui donne une indication sur la puissance offensive.
        /// Cet indice est très important, couplé avec l'efficacité.
        /// Le nombre de canons est prépondérant.
        /// </summary>
        /// <returns></returns>
        public double DonnerPuissanceOffensive()
        {
            return (this.ModificateurPuissance) * (3 * this.Canons + this.Equipage + this.Greement + this.Influence);
        }

        /// <summary>
        /// Regroupe l'efficacité offensive ainsi qu'en manoeuvre
        /// </summary>
        /// <returns></returns>
        public double DonnerEfficacite()
        {
            double efficacite = 100;
            double effetInfluence = (100 - this.Influence) / 20;
            
            // Optimal : 3 hommes par canon + 2 hommes par % de gréément
            double compte = (3 * this.Canons + 2 * this.Greement);

            if (compte > this.Equipage)
                efficacite -= this.Equipage / compte * 100;

            return this.ModificateurEfficacite + efficacite - effetInfluence;
        }

        /// <summary>
        /// Donne le nombre de tours restants de vivres.
        /// </summary>
        public Int32 DonnerToursRestantsVivres()
        {
            return Convert.ToInt32(Math.Truncate(this.Vivres / (this.Equipage * this.Consommation)));
        }
    }
}
